home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / COMM / JMOD310.ARJ / JMODEM_A.C < prev    next >
Text File  |  1991-11-30  |  39KB  |  602 lines

  1. /****************************************************************************/
  2. /*    FILE JMODEM_A.C                                                       */
  3. /*                                                                          */
  4. /*    The JMODEM protocol            MicroSoft (r)  'C' V6.00               */
  5. /*    Created 03-FEB-1990            Richard B. Johnson                     */
  6. /*                                   405 Broughton Drive                    */
  7. /*                                   Beverly, Massachusetts 01915           */
  8. /*                                   BBS (508) 922-3166                     */
  9. /*                                                                          */
  10. /*    An external protocol for high-speed data transmission.                */
  11. /*                                                                          */
  12. /*    This is the MAIN module                                               */
  13. /*    The required modules are:                                             */
  14. /*    JMODEM.H    (function prototypes and structures)                      */
  15. /*    UART.H      (8250 UART parameters)                                    */
  16. /*    SCREEN.H    (function protypes and structures for the screen)         */
  17. /*    JMODEM_A.C   (this module)                                            */
  18. /*    JMODEM_B.C   (memory allocation and input parsing)                    */
  19. /*    JMODEM_C.C   (all file I/O)                                           */
  20. /*    JMODEM_D.C   (encode/decode and CRC routines)                         */
  21. /*    JMODEM_E.C   (communications I/O routines)                            */
  22. /*    JMODEM_F.C   (the screen I/O routines)                                */
  23. /*    JMODEM_G.ASM (Interrupt service routines after V3.10)                 */
  24. /*    JMODEM.      (The MAKE file )                                         */
  25. /*                                                                          */
  26. /*    This program requires about 67k of free RAM to execute properly.      */
  27. /*    If you have 66k or less, it will execute, but the screens will        */
  28. /*    not be written or replaced properly. If you have only 64k, the        */
  29. /*    program will exit with an error message.                              */
  30. /*                                                                          */
  31. /*    Revision History:                                                     */
  32. /*    V3.00   Beta test                  11-FEB-1990   Richard B. Johnson   */
  33. /*    V3.01   First release              18-FEB-1990   Richard B. Johnson   */
  34. /*    V3.02   Revised                    19-FEB-1990   Richard B. Johnson   */
  35. /*                                                                          */
  36. /*      (1)   A bug in MicroSoft _calloc()  allocates overlapping           */
  37. /*            buffers so data files were getting corrupted. I had           */
  38. /*            used both _calloc() and _malloc() at the same time and        */
  39. /*            they didn't like it. I changed the memory allocation          */
  40. /*            to _malloc() only and it seems to work okay.                  */
  41. /*                                                                          */
  42. /*      (2)   While debugging, I found some structures I didn't need and    */
  43. /*            removed them. Changed some code to accommodate.               */
  44. /*                                                                          */
  45. /*      (3)   Added a file-size during downloads.                           */
  46. /*                                                                          */
  47. /*      (4)   Changed code in the data encoding (compression) routine       */
  48. /*            in an attempt to speed it up.                                 */
  49. /*                                                                          */
  50. /*    V3.03   Revised                   20-FEB-1990  Richard B. Johnson     */
  51. /*                                                                          */
  52. /*      (5)   Fixed bug in compression routine where the loop wasn't        */
  53. /*            terminating properly, adding random characters. Bug was       */
  54. /*            created during V3.02 change.                                  */
  55. /*                                                                          */
  56. /*    V3.04   Revised                   27-FEB-1990  Richard B. Johnson     */
  57. /*                                                                          */
  58. /*      (1)   Modified the block-size routine and the receive-block         */
  59. /*            routine in an attempt to improve the noise immunity.          */
  60. /*            Does not abort even if you whistle into the telephone         */
  61. /*            during uploads and downloads. Waits 5 seconds to clear        */
  62. /*            the interrupt buffer when a bad block-size is received.       */
  63. /*                                                                          */
  64. /*      (2)   Added a 1/2 second wait for modem status when opening         */
  65. /*            channel. This might accommodate slow modems response to       */
  66. /*            RTS.                                                          */
  67. /*                                                                          */
  68. /*    V3.05   Revised                   22-MAR-1990  Richard B. Johnson     */
  69. /*                                                                          */
  70. /*      (1)   Removed _sprintf() runtime library calls to shorten           */
  71. /*            the code. Saved about 4k.                                     */
  72. /*                                                                          */
  73. /*      (2)   Removed extra spaces in the signon-logo to shorten            */
  74. /*            the program size.                                             */
  75. /*                                                                          */
  76. /*      (3)   Changed the method of creating a fixed-length string          */
  77. /*            for both the block size and cps numbers which saved about     */
  78. /*            800 bytes of program size.                                    */
  79. /*                                                                          */
  80. /*      (4)   Changed numerous array indexes in JMODEM_F.C to pointers      */
  81. /*            to reduce code size. Saved a few hundred bytes and should     */
  82. /*            improve speed of screen output.                               */
  83. /*                                                                          */
  84. /*      (5)   Created a local _puts() routine which saved over 6k from the  */
  85. /*            MicroSoft C runtime library version. (JMODEM_F.C)             */
  86. /*                                                                          */
  87. /*    V3.06   Revised                   07-APR-1990  Richard B. Johnson     */
  88. /*                                                                          */
  89. /*      (1)   Put the filename text into the syst structure as a pointer    */
  90. /*            to char. This allowed me to save 56 bytes of code and now     */
  91. /*            only two parameters are passed to the _screen() function.     */
  92. /*                                                                          */
  93. /*      (2)   Modified the syst structure and supporting code.              */
  94. /*                                                                          */
  95. /*      (3)   Moved all external data and functions to the JMODEM.H file.   */
  96. /*                                                                          */
  97. /*      (4)   Moved _disp() "usage" module to JMODEM_F.C                    */
  98. /*                                                                          */
  99. /*      (5)   Changed arrays in JMODEM_B.C to pointers to reduce code-      */
  100. /*            size. Eliminated _strcpy() from the command-line parsing      */
  101. /*            routines. Brought the code-size to less than 12,000 bytes.    */
  102. /*                                                                          */
  103. /*      (6)   Reduced the code-size in the _encode(), _decode(), and        */
  104. /*            _crc() routines in JMODEM_D.C. Removed shifts to improve      */
  105. /*            speed and replaced the shifts with pointers for altering      */
  106. /*            portions of the strings.                                      */
  107. /*                                                                          */
  108. /*      (7)   Made a _cancel() routine in JMODEM_A.C to send ^Xes upon      */
  109. /*            abort.                                                        */
  110. /*                                                                          */
  111. /*      (8)   Removed the bit being set "OUT 1" via the modem-control       */
  112. /*            register in the "open" routine in JMODEM_E.C. This was        */
  113. /*            causing some internal modems to lock up as they use this      */
  114. /*            bit for something. "OUT 2" is used to enable IRQ on most      */
  115. /*            clone RS-232 boards and modems. The Heathkit HZ-100 boards    */
  116. /*            will probably not work anymore because they use "OUT 1".      */
  117. /*                                                                          */
  118. /*                                                                          */
  119. /*    V3.07   Revised                   03-MAY-1990  Richard B. Johnson     */
  120. /*                                                                          */
  121. /*      (1)   Rewrote code to remove the requirement for a file buffer.     */
  122. /*            This means that this buffer does not need to be allocated,    */
  123. /*            saving about 8k of RAM at run-time.  ( JMODEM_A.C )           */
  124. /*                                                                          */
  125. /*            Program now only requires 52k of free RAM to execute okay.    */
  126. /*                                                                          */
  127. /*      (2)   Changed the header file, JMODEM.H, and function calling       */
  128. /*            procedures to file_io() and screen() to allow variable-       */
  129. /*            length parameter-lists. This eliminates the requirement       */
  130. /*            to pass a NULL as a place-holder on procedures that don't     */
  131. /*            always require all possible parameters to be passed. This     */
  132. /*            saved about 50 bytes of code.                                 */
  133. /*                                                                          */
  134. /*      (3)   Changed the "Usage" prompt and code to reduce program size.   */
  135. /*            Saved about 60 bytes.                                         */
  136. /*                                                                          */
  137. /*      (4)   Changed keyboard break interrupt in JMODEM_E.C so it sets     */
  138. /*            the global timer to zero as well as setting the abort flag.   */
  139. /*                                                                          */
  140. /*    V3.08   Revised                   01-DEC-1990  Richard B. Johnson     */
  141. /*                                                                          */
  142. /*      (1)   Changed the code to compile without warning errors when       */
  143. /*            using Microsoft Version 6.0. They saw fit to change the       */
  144. /*            ANSI standards for declaring objects passed to functions.     */
  145. /*            The new "standards" were called to my attention by            */
  146. /*            Jeff Jevnisek who provided modified source.                   */
  147. /*                                                                          */
  148. /*      (2)   Changed the method of determining a memory allocation         */
  149. /*            failure. The code used to check for a NULL pointer returned   */
  150. /*            from _malloc() if memory was not available. Microsoft does    */
  151. /*            not allow NULL to be used for that anymore! Instead I have    */
  152. /*            to either use a cast or check for (!ptr). I chose the latter. */
  153. /*                                                                          */
  154. /*    V3.09   Revised                   27-JUN-1991  Richard B. Johnson     */
  155. /*                                                                          */
  156. /*      (1)   Changed a typo in the previous revision record that showed    */
  157. /*            the date to be 01-DEC-1991 when it should be 01-DEC-1990      */
  158. /*                                                                          */
  159. /*      (2)   Changed the method of checking the interrupt buffer pointer   */
  160. /*            in JMODEM_E.C so that only one compare and no arithmetic      */
  161. /*            has to be done. JMODEM now works at 38,400 baud with a        */
  162. /*            33 MHz '386 machine.                                          */
  163. /*                                                                          */
  164. /*      (3)   Added support for using any communications port address       */
  165. /*            and IRQ.                                                      */
  166. /*                                                                          */
  167. /*            JMODEM R(3F8:4) filename.typ                                  */
  168. /*            JMODEM R(2F8:3) filename.typ                                  */
  169. /*            JMODEM S(3F8:4) filename.typ                                  */
  170. /*            JMODEM S(2F8:3) filename.typ                                  */
  171. /*            JMODEM S(20E:7) filename.typ  ... etc.                        */
  172. /*                                                                          */
  173. /*    V3.10   Revised                   19-NOV-1991  Richard B. Johnson     */
  174. /*                                                                          */
  175. /*      (1)   Changed the memory allocation method. Used to allocate 4      */
  176. /*            buffers with 4 calls to _malloc(). Now I allocate one large   */
  177. /*            block and cut it up into 4 pieces. This is more efficient.    */
  178. /*                                                                          */
  179. /*      (2)   Called _malloc() directly without a separate allocate_mem()   */
  180. /*            routine because machine differences can be handled with       */
  181. /*            definitions for different compilers and platforms.            */
  182. /*                                                                          */
  183. /*      (3)   Moved the receive and timer interrupt service routines to     */
  184. /*            assembly-language modules in JMODEM_G.ASM                     */
  185. /*                                                                          */
  186. /*                                                                          */
  187. /****************************************************************************/
  188. #include <stdlib.h>                     /* Used for _free()                 */
  189. #include <stdio.h>                      /* Used for NULL value              */
  190. #include <string.h>                     /* Used for _memcpy()               */
  191. #include <time.h>                       /* Used for absolute time           */
  192. #include "jmodem.h"                     /* JMODEM primatives                */
  193. #if defined (TURBOC)
  194.     #include <alloc.h>
  195. #else
  196.     #include <malloc.h>                 /* Used for _malloc();              */
  197. #endif
  198.  
  199. /****************************************************************************/
  200. /*                   Global pointers and allocation                         */
  201. /****************************************************************************/
  202. word user_abort = 0;                    /* Global user abort flag           */
  203. byte *int_buffer;                       /* Pointer to interrupt buffer      */
  204. SYS syst;                               /* Structure for JMODEM status      */
  205. /****************************************************************************/
  206. /*                               C O D E                                    */
  207. /****************************************************************************/
  208. short main (short argc,  char *argv[])
  209. {
  210.     byte *in_buffer;                      /* Pointer to input buffer        */
  211.     byte *out_buffer;                     /* Pointer to output buffer       */
  212.     byte *comp_buffer;                    /* Pointer to compression buffer  */
  213.     register byte *io_ptr;                /* Select buffers to use for I/O  */
  214.     register JBUF *buff;                  /* A pointer for the JMODEM block */
  215.     byte *file_name;                      /* Filename                       */
  216.     byte function;                        /* Receive, Transmit              */
  217.     time_t start;                         /* Start time                     */
  218.     time_t finish;                        /* End time                       */
  219. #ifdef FTIME                              /* Floating point timer           */
  220.     double dat_tmp;                       /* Temporary variable for time    */
  221. #endif
  222.     word status=0;                        /* TX and RX status               */
  223.     word tries;                           /* Attempts to send a file        */
  224.     word cmp_size;                        /* Size after compression         */
  225.     word data_written;                    /* Data written to the file       */
  226.     word data_read;                       /* Data read from the file        */
  227.     short handle;                         /* For file I/O                   */
  228.  
  229.     if (!(file_name = get_inp (argc, argv))) /* Get file name               */
  230.     {
  231.         disp();                              /* Display usage message       */
  232.         return JM_FNF;
  233.     }
  234.     if (!(function = get_fun (argc, argv)))  /* Get function 'R' or 'S'     */
  235.     {
  236.         disp();                              /* Display usage message       */
  237.         return JM_CMD;
  238.     }
  239.     if (!(port = get_port (argc, argv)))     /* Get port '1 to 4 '          */
  240.     {
  241.         disp();                              /* Display usage message       */
  242.         return JM_CMD;
  243.     }
  244. /****************************************************************************/
  245. /*                          Allocate buffers                                */
  246. /*  Note: Here I allocate one large buffer that is 4 times the size of      */
  247. /*        DAT_LEN. Then I partition it into 4 sections for the 4 buffers.   */
  248. /*        This is more efficient that multiple calls to _malloc() and I     */
  249. /*        can free the entire buffer with one call to _free().              */
  250. /****************************************************************************/
  251.     in_buffer = (byte *) malloc(ALC_MEM);  /* Get some memory for input     */
  252.     if (!in_buffer)
  253.         return JM_MEM;                     /* No memory available           */
  254.     out_buffer = in_buffer   + DAT_LEN;    /* Get some memory for output    */
  255.     comp_buffer= out_buffer  + DAT_LEN;    /* Get memory for compression    */
  256.     int_buffer = comp_buffer + DAT_LEN;    /* Memory for interrupt buffer   */
  257. /****************************************************************************/
  258.     screen (SCR_SGN);                      /* Write signon screen           */
  259.     syst.s_len = BLK_SIZ;                  /* Set beginning block size      */
  260.     syst.s_byt = 0;                        /* Set bytes handled             */
  261.     syst.s_blk = 0;                        /* Starting block                */
  262.     syst.s_sta = okay;                     /* Starting status               */
  263.     switch(function)                       /* Functions are TX and RX       */
  264.     {
  265. /****************************************************************************/
  266. /*                          Receive JMODEM file                             */
  267. /****************************************************************************/
  268.     case 'R':
  269.         {
  270.             if (!file_io(CREATE, &handle, file_name) )
  271.             {
  272.                 buff = (JBUF *) in_buffer;           /* Assign type JBUF    */
  273.                 open_chan(port);                     /* Open com channel    */
  274.                 screen (SCR_STA);                    /* Write status block  */
  275.                 status = rx_sync();                  /* Synchronize         */
  276.                 if (!status)
  277.                     screen (SCR_SYR);
  278.                 data_written = 0xFFFF;
  279.                 tries = 10;                          /* Attempts to receive */
  280.                 while (    (data_written)            /* Write file okay     */
  281.                         && (!user_abort )            /* No break key        */
  282.                         && (!status     )            /* Recev block okay    */
  283.                         && (tries--)    )            /* 10 retries          */
  284.                 {
  285.                     time(&start);                    /* Get starting time   */
  286.                     screen (SCR_SYS,&syst);          /* Show status block   */
  287.                     status = recv_blk (              /* Receive data-block  */
  288.                              &syst.s_len,            /* Block length        */
  289.                              in_buffer);             /* Input buffer        */
  290.                     if (status)                      /* If bad              */
  291.                         break;                       /* Abort the WHILE     */
  292.                     if( (!(calc_crc( GET_CRC,        /* Calculate CRC       */
  293.                           syst.s_len,                /* Amount to check     */
  294.                           in_buffer) ))              /* Receiver buffer     */
  295.                       && ( buff->blk_num ==          /* Check block also    */
  296.                          (byte)
  297.                          (syst.s_blk +1)))           /* Block number        */
  298.                     {
  299.                         syst.s_sta = okay;           /* Text pointer        */
  300.                         tries=10;                    /* Reset count         */
  301.                         syst.s_len -= OVRHD;         /* Subtract overhead   */
  302.                         *out_buffer = ACK;           /* Good                */
  303.                         write_chan(1,out_buffer);    /* Send the ACK        */
  304.                         io_ptr = &buff->blk_dat;     /* Assume normal data  */
  305.  
  306.                         if (buff->blk_typ & COMP)
  307.                         {                            /* If data compressed  */
  308.                              syst.s_len = decode (   /* Decode the data     */
  309.                                       syst.s_len,    /* Data-block length   */
  310.                                      &buff->blk_dat, /* Where to start      */
  311.                                      comp_buffer);   /* Where to put data   */
  312.                              io_ptr = comp_buffer;   /* Point to data       */
  313.                         }
  314.                         data_written = file_io(WRITE, /* Write to file      */
  315.                                          &handle,     /* File handle        */
  316.                                          io_ptr ,     /* Where data is      */
  317.                                          syst.s_len); /* Amount to write    */
  318.                         syst.s_byt += data_written;   /* Total bytes        */
  319.                         syst.s_blk++;                 /* Block number       */
  320.                         time(&finish);                /* Get end time       */
  321.                         if (finish - start)           /* Check div/0        */
  322.                         {
  323. #ifdef FTIME
  324.                             dat_tmp = (double) data_written;
  325.                             syst.s_cps = (short) (dat_tmp /
  326.                                                difftime(finish,start));
  327. #else
  328.                             syst.s_cps = (short)      /* Calc Block CPS     */
  329.                             (data_written / (finish - start) );
  330. #endif
  331.                         }
  332.                                                        /* Check end-of-file */
  333.                         if (buff->blk_typ & EOF_)
  334.                         {
  335.                             file_io(CLOSE,&handle);   /* Close file         */
  336.                             close_chan(port);         /* Close the port     */
  337.                             status = JM_NRM;          /* Set status         */
  338.                             goto cleanup;             /* exit routine       */
  339.                         }
  340.                     }
  341.                     else
  342.                     {
  343.                         *out_buffer = NAK;            /* Bad block          */
  344.                         syst.s_sta = retry;           /* Char pointer       */
  345.                         write_chan(1,out_buffer);     /* Send the NAK       */
  346.                      }
  347.                 }
  348.                 close_chan(port);                     /* Aborted            */
  349.                 file_io( DELETE, &handle, file_name); /* Delete bad file    */
  350.                 status = JM_ABT;
  351.                 break;                                /* Exit if() {}       */
  352.             }
  353.             else                                      /* Can't create file  */
  354.             {
  355.                 status = JM_CRE;
  356.                 break;                                /* Exit while() {}    */
  357.             }
  358.         }
  359. /****************************************************************************/
  360. /*                          Send JMODEM file                                */
  361. /****************************************************************************/
  362.     case 'S':   /* Send JMODEM file */
  363.         {
  364.             if (!file_io(OPEN_READ, &handle, file_name) )
  365.             {
  366.                 buff = (JBUF *)out_buffer;            /* Assign type JBUF   */
  367.                 syst.s_byt = 0;                       /* Restore byte count */
  368.                 open_chan(port);                      /* Open COM port      */
  369.                 screen (SCR_STA);                     /* Write status block */
  370.                 status = tx_sync();                   /* Synchronize        */
  371.                 if (!status)
  372.                     screen (SCR_SYT);
  373.                 while  ( (!user_abort)                /* Ctrl - break       */
  374.                        && (!status) )                 /* sent okay          */
  375.                 {
  376.                     time(&start);                     /* Get starting time  */
  377.                     data_read = file_io( READ,        /* Read a record      */
  378.                                       &handle,        /* File pointer       */
  379.                                       &buff->blk_dat, /* Where to put data  */
  380.                                       syst.s_len );   /* Amount to read     */
  381.                     if (!data_read)                   /* Past end of file   */
  382.                         break;
  383.                     syst.s_byt += (long) data_read;   /* Running count      */
  384.                     screen (SCR_SYS,&syst);           /* Show status block  */
  385.                     buff->blk_num = (byte)
  386.                                      ++syst.s_blk;    /* Block number       */
  387.                     buff->blk_typ = NORM;             /* Assume Normal      */
  388.                     buff->len = (data_read+OVRHD);    /* Length of block    */
  389.                     if (data_read != syst.s_len)      /* Less than request  */
  390.                         buff->blk_typ |= EOF_;        /* Its end of file    */
  391.                     cmp_size = encode (data_read,     /* Encode size        */
  392.                                       &buff->blk_dat, /* Source             */
  393.                                       comp_buffer);   /* Destination        */
  394.                     if ( cmp_size  < data_read  )     /* If compressed      */
  395.                     {
  396.                         buff->len = (cmp_size+OVRHD); /* Length of block    */
  397.                         buff->blk_typ |= COMP;        /* Show compressed    */
  398.                         memcpy (&buff->blk_dat,       /* Start of data      */
  399.                                    comp_buffer,       /* Copy from here     */
  400.                                    cmp_size);         /* This much          */
  401.                     }
  402.                     calc_crc(SET_CRC,                 /* Calculate CRC      */
  403.                             buff->len ,               /* Length of block    */
  404.                             out_buffer);              /* Where data is      */
  405.                     status = send_blk(                /* Send the block     */
  406.                              buff->len,               /* Block length       */
  407.                              &syst,                   /* Read block ptr.    */
  408.                              out_buffer);             /* Buffer pointer     */
  409.                     time(&finish);                    /* Get end time       */
  410.                     if (finish - start)               /* Check div/0        */
  411.                     {
  412. #ifdef FTIME
  413.                         dat_tmp = (double) data_read;
  414.                         syst.s_cps = (short) (dat_tmp /
  415.                                      difftime(finish,start));
  416. #else
  417.                         syst.s_cps = (short)          /* Calc Block CPS     */
  418.                         (data_read / (finish - start) );
  419. #endif
  420.                     }
  421.                     if ( buff->blk_typ == EOF_)       /* Last record        */
  422.                         break;
  423.                 }
  424.                 syst.s_sta = done;                    /* Assume normal      */
  425.                 if (status)
  426.                 {
  427.                     cancel();                         /* Send ^Xes          */
  428.                     syst.s_sta = abrt;                /* Was aborted        */
  429.                 }
  430.                 close_chan(port);                     /* Close the port     */
  431.                 file_io(CLOSE, &handle);              /* Close the file     */
  432.                 screen (SCR_SYS,&syst);               /* Show status block  */
  433.             }
  434.             else                                      /* File not found     */
  435.             {
  436.                 status = JM_FNF;
  437.             }
  438.         break;                                        /*   End of CASE 'S'  */
  439.         }
  440.     }
  441.     cleanup:
  442.     free (in_buffer);                                 /* Free  buffers      */
  443.                               /* Two-second timer to display error messages */
  444.     if (status != JM_NRM)
  445.     {
  446.         time(&finish);                               /* Get system clock    */
  447.         finish += 2;                                 /* Add two seconds     */
  448.         start = 0;
  449.         while ( finish > start )                     /* Wait until the same */
  450.             time(&start);
  451.     }
  452.     screen (SCR_END);                                /* Clear the screen    */
  453.     return status;                                   /* Normal exit         */
  454. }
  455. /****************************************************************************/
  456. /*                          Send the JMODEM block                           */
  457. /****************************************************************************/
  458. word send_blk (word blk_len, register SYS *sys_ptr, register byte *buffer)
  459. {
  460.     byte ack_buf;                         /* Buffer for ACK/NAK             */
  461.     word tries = 10;                      /* Attempts to send the block     */
  462.     while ((tries--) && (!user_abort))
  463.     {
  464.         write_chan(blk_len,buffer);       /* Send the JMODEM block          */
  465.         flush();                          /* Clear back channel noise       */
  466.         do
  467.         {
  468.             ack_buf = (char) 0x00;        /* Clear the return buffer        */
  469.             read_chan(1,&ack_buf);        /* Receive a response             */
  470.         } while ( (ack_buf != ACK)        /* Stay in loop until we          */
  471.                && (ack_buf != CAN)        /*  ... get something useful      */
  472.                && (ack_buf != NAK)        /* This helps re-sync in noise    */
  473.                && (ack_buf == (char) 0x00)
  474.                && (!user_abort) );
  475.  
  476.         if ( (ack_buf == CAN)
  477.            || user_abort )                /* Check for an abort             */
  478.             break;                        /* User aborted                   */
  479.         if (ack_buf == ACK)               /* If good block                  */
  480.         {
  481.             if (tries == 9)               /* If no retries                  */
  482.             {
  483.                 sys_ptr->s_len += 512;    /* Increase block-size            */
  484.                 if (sys_ptr->s_len > DAT_MAX) /* If too large               */
  485.                     sys_ptr->s_len = DAT_MAX;
  486.             }
  487.             else
  488.             {
  489.                 tries = 9 - tries;        /* Use for divisor                */
  490.                 sys_ptr->s_len =          /* Update block length            */
  491.                 sys_ptr->s_len / tries;   /* Div block size                 */
  492.             if (sys_ptr->s_len < 0x40)    /* If less than minimum           */
  493.                 sys_ptr->s_len = 0x40;    /* Set to minimum                 */
  494.             }
  495.         sys_ptr->s_sta = okay;            /* Show status is okay            */
  496.         return JM_NRM;                    /* Show good                      */
  497.         }
  498.     sys_ptr->s_sta = retry;               /* Show a retry                   */
  499.     screen (SCR_SYS, sys_ptr);            /* Write to screen                */
  500.     }
  501.     cancel();                             /* Send cancel (^Xes)             */
  502.     return JM_ABT;                        /* Abort local program            */
  503. }
  504. /****************************************************************************/
  505. /*                        Receive the JMODEM block                          */
  506. /****************************************************************************/
  507. word recv_blk (word *blk_len, register byte *buffer)
  508. {
  509.     register JBUF *buff;                  /* Pointer type JBUF              */
  510.     byte nak_buf;                         /* Buffer for ACK/NAK             */
  511.     word tries = 10;                      /* Attempts to receive the block  */
  512.     word ret_val;                         /* Block length returned          */
  513.     buff = (JBUF * )buffer;               /* Assign pointer type JBUF       */
  514.  
  515.     while ((tries--) && (!user_abort))
  516.     {
  517.         ret_val = read_chan(2,buffer);    /* Receive the block size         */
  518.         if (ret_val == 2)                 /* If we received the length      */
  519.         {
  520.             *blk_len = buff->len;         /* So caller knows size           */
  521.             if (*blk_len > DAT_LEN)       /* If way out of line             */
  522.                 break;                    /* NAK it                         */
  523.             ret_val = read_chan(          /* Get more data                  */
  524.                       (*blk_len)-2 ,      /* Size to read                   */
  525.                       &buff->blk_typ);    /* Where to put it                */
  526.             if (ret_val == (*blk_len)-2)  /* If we got what we requested    */
  527.                 return JM_NRM;
  528.         }
  529.     if (buff->blk_typ == CAN)             /* If transmitter sent ^Xes       */
  530.         break;                            /* The other side has aborted     */
  531.     read_chan (DAT_LEN,buffer);           /* Make sure other end stops      */
  532.     nak_buf = NAK;                        /* Get a NAK                      */
  533.     write_chan(1,&nak_buf);               /* Send to remote                 */
  534.     flush();                              /* Flush the buffer               */
  535.     }
  536.     cancel();                             /* Send cancel (^Xes)             */
  537.     return JM_ABT;                        /* Abort local program            */
  538. }
  539. /****************************************************************************/
  540. /*                         Synchronize during receive                       */
  541. /****************************************************************************/
  542. word rx_sync()
  543. {
  544.     byte ack_nak;                         /* Single byte buffer for ACK/NAK */
  545.     flush();                              /* Clear the interrupt buffer     */
  546.     while (!user_abort)
  547.     {
  548.         ack_nak = (char) 0x00;            /* Clear the buffer               */
  549.         read_chan(1,&ack_nak);            /* Receive ACK, NAK, or SYN       */
  550.         if (ack_nak == CAN)               /* If a ^X                        */
  551.             break;
  552.         if ( ack_nak == ACK )             /* If a good response             */
  553.             return JM_NRM;                /* Show handshake                 */
  554.         if ( ack_nak == NAK )             /* If a good response             */
  555.         {
  556.             ack_nak = ACK;
  557.             write_chan(1,&ack_nak);       /* Send a ACK response            */
  558.             return JM_NRM;
  559.          }
  560.          ack_nak = NAK;
  561.          write_chan(1,&ack_nak);          /* Keep sending NAKs              */
  562.     }
  563.     cancel();                             /* Send cancel (^Xes)             */
  564.     return JM_ABT;
  565. }
  566. /****************************************************************************/
  567. /*                           Send ^Xes to cancel                            */
  568. /****************************************************************************/
  569. void cancel()
  570. {
  571.     byte buffer = CAN;
  572.     short xes = 6;
  573.     user_abort=0;                         /* Reset flag so write_chan works */
  574.     while(xes--)
  575.         write_chan(1,&buffer);
  576. }
  577. /****************************************************************************/
  578. /*                         Synchronize during transmit                      */
  579. /****************************************************************************/
  580. word tx_sync()
  581. {
  582.     word ret_val;
  583.     ret_val = rx_sync();                /* Call same routine for receive    */
  584.     if (!ret_val)                       /* If success                       */
  585.     {
  586.         flush();                        /* Flush the input buffer           */
  587.         timer = 5;                      /* 5 timer-ticks to wait            */
  588.         while (timer);                  /* Wait for timer                   */
  589.     }
  590.     return ret_val;                     /* Return status                    */
  591. }
  592. /****************************************************************************/
  593. /*     Dummy _setenvp procedure to replace the large library module         */
  594. /****************************************************************************/
  595. #ifdef NOENV                            /* If a compiler command            */
  596. void _setenvp(void);                    /* Dummy routine prototype          */
  597. void _setenvp()                         /* Dummy routine                    */
  598. {}
  599. #endif
  600. /****************************************************************************/
  601. /************************ E N D  O F   M O D U L E **************************/
  602.